import { cadAppWarnLog, ExtensionID } from '@amcax/base';
import { docMgr, previewer } from '@app-cad/module';
import { wsApi } from '@app-cad/server';
import { useEffect, useRef } from 'react';
import { previewData } from '../utils/render';

export const useTransaction = (needPreview = true) => {
  const isInTransaction = useRef(false);
  const initPromiseRef = useRef<Promise<void>>();

  const start = async (n: string) => {
    const startPromise = new Promise<void>(async (resolve, reject) => {
      if (isInTransaction.current) resolve();

      try {
        await wsApi.startTransaction({
          n,
          l: `${n}-${Date.now()}`,
          e: ExtensionID.CAD,
        });

        isInTransaction.current = true;

        resolve();
      } catch {
        reject();
      }
    });

    if (initPromiseRef != null) {
      initPromiseRef.current = startPromise;
      await startPromise;
    }
  };

  const edit = async (params: any, type: string) => {
    const editPromise = new Promise<void>(async (resolve, reject) => {
      if (isInTransaction.current) resolve();

      try {
        await initPromiseRef.current;
        await wsApi.startTransaction({
          n: 'SetParams',
          l: `${type}-${Date.now()}`,
          e: ExtensionID.CAD,
        });
        await setArguments(params, true);

        isInTransaction.current = true;

        resolve();
      } catch (e) {
        reject(e);
      }
    });

    if (initPromiseRef != null) {
      initPromiseRef.current = editPromise;
      await editPromise;
    }
  };

  const setArguments = async (params: any, skipInitCheck = false) => {
    if (!skipInitCheck) {
      await initPromiseRef.current;

      if (!isInTransaction.current) {
        cadAppWarnLog('setArguments前应先执行start/edit');
        return;
      }
    }

    await wsApi.setArguments(params);
  };

  const execute = async (params: any) => {
    await initPromiseRef.current;

    if (!isInTransaction.current) {
      cadAppWarnLog('execute前应先执行start/edit');
      return null;
    }

    const {
      data: previewPart,
      nsolution,
      Profile: profile,
    } = await wsApi.executeTransaction(
      { ...params, parent: docMgr.workingObjectDxid },
      true,
    );

    if (needPreview) {
      previewData(previewPart, profile);
    }

    return { previewPart, nsolution };
  };

  const finish = async (
    params: any,
    callback: (p: typeof params) => Promise<void>,
  ) => {
    if (!isInTransaction.current) return;
    if (needPreview) {
      previewer.clear();
    }

    await callback(params);

    isInTransaction.current = false;
  };

  const end = async (params: any = {}) => finish(params, wsApi.endTransaction);
  const abort = async (params: any = {}) =>
    finish(params, wsApi.abortTransaction);

  useEffect(
    () => () => {
      abort();
    },
    [],
  );

  return {
    start,
    edit,
    setArguments,
    execute,
    end,
    abort,
    clear: () => {
      previewer.clear();
    },
  };
};
